<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>File: module_doc.rb [RDoc Documentation]</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta http-equiv="Content-Script-Type" content="text/javascript" />
  <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
  <script type="text/javascript">
  // <![CDATA[

  function popupCode( url ) {
    window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
  }

  function toggleCode( id ) {
    if ( document.getElementById )
      elem = document.getElementById( id );
    else if ( document.all )
      elem = eval( "document.all." + id );
    else
      return false;

    elemStyle = elem.style;

    if ( elemStyle.display != "block" ) {
      elemStyle.display = "block"
    } else {
      elemStyle.display = "none"
    }

    return true;
  }

  // Make codeblocks hidden by default
  document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }<\/style>" )

  // ]]>
  </script>

</head>
<body>


  <div id="fileHeader">
    <h1>module_doc.rb</h1>
    <table class="header-table">
    <tr class="top-aligned-row">
      <td><strong>Path:</strong></td>
      <td>rcapture/module_doc.rb

      </td>
    </tr>
    <tr class="top-aligned-row">
      <td><strong>Last Update:</strong></td>
      <td>2010-02-20 15:27:03 +0100</td>
    </tr>
    </table>
  </div>
  <!-- banner header -->

  <div id="bodyContent">

  <div id="contextContent">

    <div id="description">
      <h1>Introduction</h1>
<p>
The module <a href="../../classes/RCapture.html">RCapture</a> is your
single entry point when it comes to method capturing/hooking.
</p>
<p>
To hook/capture methods you need to
</p>
<ul>
<li>enrich target(s) with capturing capatibilities. This is provided by the
module mixin Interceptable.

</li>
<li>capture the methods by invoking methods from Interceptable.

</li>
</ul>
<h1>Examples</h1>
<p>
Here is a set of examples that should help you getting started. Those
examples are part of the <a href="../../classes/RCapture.html">RCapture</a>
distribution
</p>
<h2>Hello World</h2>
<p>
The following example illustrates basic class and instance level hooking
and makes use of the passed CapturedInfo instance to query details.
</p>
<pre>
  require 'rcapture'

  # Enrich Array class.
  class Array
    include RCapture::Interceptable
  end

  # Install a hook at insertion methods of Array.
  # Calling capture methods at class level will capture
  # insertions from all instances of Array.
  Array.capture_pre :methods =&gt; [:&lt;&lt;, :push] do |cs|
    puts &quot;'#{cs.method}' will be called with #{cs.args.first}&quot;
  end

  [] &lt;&lt; 1 &lt;&lt; 2
  [].push :hello

  # Installing a hook on instance level will
  # affect only that single instance
  a = []
  a.capture_post :methods =&gt; :length do |cs|
    puts &quot;Length of 'a' is #{cs.return}&quot;
  end

  a &lt;&lt; 1
  a.length

  # Any other array will not be affected
  [].length

  #=&gt; '&lt;&lt;' was called with 1!
  #=&gt; '&lt;&lt;' was called with 2!
  #=&gt; 'push' was called with hello!
  #=&gt; '&lt;&lt;' was called with 1!
  #=&gt; Length of 'a' is 1
</pre>
<h2>Class Methods</h2>
<p>
In this example quickly shows how to hook class methods.
</p>
<pre>
  require 'rcapture'

  # Enrich Math module
  module Math
    include RCapture::Interceptable
  end

  Math.capture_pre :class_methods =&gt; [:cos, :acos, :sin, :asin] do
    puts &quot;Hello Trigonometry!&quot;
  end

  Math.cos(0)

  #=&gt; Hello Trigonometry!#
</pre>
<h2>Modifying Arguments and Return Values</h2>
<p>
The following example illustrates capturing methods in order to modify
input and return arguments. Further, it illustrates how capture methods of
a single instance only.
</p>
<pre>
  require 'rcapture'

  # Enrich single instance
  x = []
  x.extend(RCapture::Interceptable)

  # Define procs that will modify the input arguments
  inc = Proc.new { |ci| ci.args[0] += 1 }
  dec = Proc.new { |ci| ci.args[0] -= 1 }
  mul = Proc.new { |ci| ci.args[0] *= 2 }

  # Capture ':&lt;&lt;' multiple times.
  x.capture_pre :methods =&gt; :&lt;&lt;, &amp;inc
  x.capture_pre :methods =&gt; :&lt;&lt;, &amp;mul
  x.capture_pre :methods =&gt; :&lt;&lt;, &amp;inc
  x.capture_pre :methods =&gt; :&lt;&lt;, &amp;dec
  x.capture_pre :methods =&gt; :&lt;&lt;, &amp;dec

  x &lt;&lt; 2 &lt;&lt; 4
  p x
  #=&gt; [3,7]

  # Similarily, you can modify return values
  y = []
  y.extend(RCapture::Interceptable)

  inc = Proc.new { |ci| ci.return += 1 }
  dec = Proc.new { |ci| ci.return -= 1 }
  mul = Proc.new { |ci| ci.return *= 2 }

  y.capture_post :methods =&gt; :[], &amp;inc
  y.capture_post :methods =&gt; :[], &amp;mul
  y.capture_post :methods =&gt; :[], &amp;inc
  y.capture_post :methods =&gt; :[], &amp;dec
  y.capture_post :methods =&gt; :[], &amp;dec

  y &lt;&lt; 1 &lt;&lt; 4
  p y[0] #=&gt; 3
  p y[1] #=&gt; 9#
</pre>
<h2>Filtering Method Calls</h2>
<p>
Additionally to modifying arguments you can prevent captured method from
being called using a Interceptable#capture_pre hook.
</p>
<pre>
  require 'rcapture'

  # This array will only accept even numbers
  x = []
  x.extend(RCapture::Interceptable)

  even_filter = Proc.new do |ci|
    # Define the predicate that must evaluate to true
    # in order to call the captured method
    ci.predicate = (ci.args.first % 2 == 0)

    # In case the predicate evaluates to false you
    # can use the return property to control
    # what is returned from the captured method instead
    # Insertion to array returns the array itself:
    ci.return = ci.sender
  end

  x.capture_pre :methods =&gt; [:&lt;&lt;, :push], &amp;even_filter

  x &lt;&lt; 2 &lt;&lt; 3 &lt;&lt; 4 &lt;&lt; 5 &lt;&lt; 6
  x.push(7).push(8)
  p x
  #=&gt; [2,4,6,8]#
</pre>
<h2>Callbacks Are Capture-Free</h2>
<p>
During processing of a callback, capturing is disabled. Otherwise, this
could lead to infinite recursion as the following examples demonstrates.
</p>
<pre>
  require 'rcapture'

  class Fixnum
    include RCapture::Interceptable
  end

  op_count = 0
  Fixnum.capture :methods =&gt; :+ do |cs|
    # Here we use Fixnum#+ inside the callback.
    # RCapture takes special care that anything that
    # happens inside a callback remains capture-free.
    op_count = op_count + 1
  end

  x = 1 + 1 + 2 + 3
  p op_count #=&gt; 3#
</pre>
<h2>Inheritance</h2>
<p>
Captured methods propagate through derivates as long as they are not
overridden by a class.
</p>
<pre>
  require 'rcapture'
  include RCapture

  # Closed polygon
  class Polygon
    include Interceptable
    def vertices; self.edges; end
  end

  # Triangle
  class Triangle &lt; Polygon
    def edges; 3; end
  end

  # Degenerate polygon
  class Digon &lt; Polygon
    def edges; 1; end
    def vertices; 2; end
  end

  # Four sided polygon
  class Quadliteral &lt; Polygon
    def edges; 4; end
    def vertices; super; end
  end

  called = 0
  Polygon.capture :methods =&gt; :vertices do
    called += 1
  end

  Triangle.new.vertices # +1
  Digon.new.vertices # -
  Quadliteral.new.vertices # +1

  p called #=&gt; 2#
</pre>
<h2>Multithreading</h2>
<p>
<a href="../../classes/RCapture.html">RCapture</a> is a lock-free
implementation that supports multithreading. There is no restriction on the
number of threads that call a shared callback. Captures, however, should be
called only from a single thread or guaranteed to be synchronized by the
user. Since callbacks can be invoked from multiple threads in parallel,
shared resources from within the callbacks need to be synchronized by the
user. The passed CapturedInfo is a thread-local variable and needs not to
be synchronized. The following example illustrates this.
</p>
<pre>
  require 'rcapture'
  require 'thread'

  # Will keep track of Enumberable#inject results
  inject_results = []
  m = Mutex.new

  module Enumerable
    include RCapture::Interceptable
  end

  Enumerable.capture :methods =&gt; :inject do |cs|
    # Callbacks can be invoked from multiple threads.
    # So we need to synchronize access to shared resources.
    m.synchronize do
      inject_results &lt;&lt; cs.return
    end
  end

  array = []
  10000.times {array &lt;&lt; rand(100)}

  threads = []
  5.times do
    t = Thread.new do
      sum = array.inject(0) {|memo, e| memo + e}
    end
    threads &lt;&lt; t
  end
  threads.each {|t| t.join }

  p inject_results #=&gt; [493311, 493311, 493311, 493311, 493311] or similar#
</pre>
<h2>New with Block</h2>
<p>
Here is one final example that stimulate your imagination of what can be
done with RCapture: given any class, it is often desireable to work with
newly created instance by passing a block to new. If that class does not
support this you can use <a href="../../classes/RCapture.html">RCapture</a>
to enable this behaviour.
</p>
<pre>
  require 'rcapture'
  include RCapture

  class X
    include Interceptable
    def initialize(name); @name = name; end
    def say_hello; puts &quot;Hello, #{@name}!&quot;; end
  end

  class Y &lt; X
    def initialize; super(&quot;Y&quot;); end
  end

  X.capture :class_methods =&gt; :new do |ci|
    ci.block.call(ci.return) if ci.block
  end

  # Now you can use X and Y as if it supports
  # blocks
  x = X.new(&quot;Christoph&quot;) do |x|
    x.say_hello #=&gt; &quot;Hello, Christoph!&quot;
  end

  y = Y.new do |y|
    y.say_hello #=&gt; &quot;Hello, Y!&quot;
  end

  # Or leaf the block argument away
  x = X.new(&quot;Christoph&quot;)
  y = Y.new#
</pre>
<h1>Benchmark</h1>
<p>
<a href="../../classes/RCapture.html">RCapture</a> works on Ruby 1.8.x and
1.9.x. Due to API changes between 1.8 and 1.9, <a
href="../../classes/RCapture.html">RCapture</a> selects an appropriate
implementation of its core methods. Here is a benchmark that illustrates
the overhead on 1.8 and 1.9 when a captured method is called.
</p>
<pre>
  require 'test/unit'
  require 'test/unit/testee'
  require 'benchmark'
  require 'rcapture'

  class Fixnum
    include RCapture::Interceptable
  end

  class BenchmarkCapture &lt; Test::Unit::TestCase

    def test_benchmark_native
      n = 100000
      puts &quot;Benchmarking addition&quot;
      Benchmark.bm do |x|
        x.report { n.times do; 1+1; end }
        Fixnum.capture :methods =&gt; :+ do
        end
        x.report { n.times do; 1+1; end }
      end

      # On my machine Intel Q6600, 2.4GHz
      #
      # Ruby 1.8.6
      # user     system      total        real
      # 0.015000   0.000000   0.015000 (  0.027000)
      # 1.610000   0.000000   1.610000 (  1.629000)
      # overhead is roughly 0,00001602 secs per invocation
      #
      # Ruby 1.9.1
      # user     system      total        real
      # 0.000000   0.000000   0.000000 (  0.009765)
      # 0.359000   0.000000   0.359000 (  0.356446)
      # overhead is roughly 0,0000034 secs per invocation
    end

    def test_benchmark_construct
      n = 100000
      puts &quot;Benchmarking construction of new objects&quot;
      Benchmark.bm do |x|
        x.report { n.times do; Testee.new; end }
        Testee.capture :class_methods =&gt; :new do
        end
        x.report { n.times do; Testee.new; end }
      end

      # On my machine Intel Q6600, 2.4GHz
      #
      # user     system      total        real
      # 0.188000   0.000000   0.188000 (  0.208000)
      # 1.812000   0.000000   1.812000 (  1.836000)
      # overhead is roughly 0,00001628 secs per invocation
      #
      # Ruby 1.9.1
      # user     system      total        real
      # 0.047000   0.000000   0.047000 (  0.051757)
      # 0.422000   0.000000   0.422000 (  0.408203)
      # overhead is roughly 0,00000357 secs per invocation
    end
  end
</pre>

    </div>

   </div>


  </div>

    <!-- if includes -->

    <div id="section">




    <!-- if method_list -->




  </div>

<div id="validator-badges">
  <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>

</body>
</html>
